package com.jse;

import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.json.Json;
import org.nutz.lang.Files;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.view.RawView;

import com.alibaba.druid.pool.DruidDataSource;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.jse.dao.Dao;
import com.jse.ioc.Ioc;
import com.jse.pay.AliPay;
import com.jse.pay.WxPay;
import com.jse.service.CacheService;
import com.jse.service.NashornService;
import com.jse.view.JseView;

import jdk.nashorn.api.scripting.NashornScriptEngine;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;

@WebFilter(displayName="jseFilter",urlPatterns="/*")
public class JseFilter implements Filter {

	Log log=Logs.get();
	Ioc ioc=Ioc.create();
	PropertiesProxy conf;
	DruidDataSource dataSource;
	Dao dao;
	NashornService nashornService;
	
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest req=(HttpServletRequest) request;
		HttpServletResponse resp=(HttpServletResponse) response;
		String path= req.getServletPath();//请求路径
		String suffix=Files.getSuffixName(path);
		if(suffix.equals("")||conf.get("mvc.prefix").contains(suffix)) {
			long start_time=System.currentTimeMillis();
			String url=path.substring(1, path.length()).replace(".".concat(suffix), "");//去除后缀的url
			String[] paths=url.split("/");
			NutMap param=new NutMap();
			if(request.getContentType()!=null&&request.getContentType().contains("multipart/form-data")) {
	    		req.getParts().forEach(part->{
	    			String name = part.getName();  
	                String fileName = getFilename(part);  
	    			if (!Strings.isEmpty(fileName)) {
	                    String str = request.getServletContext().getRealPath("/").replace("\\", "/");
	            		String appName = str.substring(0, str.lastIndexOf("/"));
	            		appName = appName.substring(appName.lastIndexOf("/"));
	            		String webPath = str.substring(0, str.indexOf("tomcat") + 7) + "webapps/";
	            		String filePath = str.substring(0, str.indexOf("tomcat") + 7) + "webapps/upload/file";
	            		try {
	            			SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
	            			String dateString = simpleDateFormat.format(new Date());
	            			String fid = UUID.randomUUID().toString();
	            			filePath = filePath +appName+"/" +  dateString + "/" + fid+"_" + fileName;
	            			part.write(filePath);
	            			filePath = filePath.replace(webPath, "");
	            			param.put(name, filePath);
	            		} catch (Exception e) {
	            			log.error("file upload copy fail! err_msg :", e);
	            		}
	                } else {  
	                    param.put(name, request.getParameter(name));
	                }  
	    		});
	    	}else {
	        	request.getParameterMap().forEach((k,v)->{
	    			param.put(k, v.length>1?Arrays.asList(v):v[0]);
	    		});
	    	}
		try {
			if(paths.length==1) {
				if(paths[0].equals("index")) {
					Object obj = nashornService.run(null,"index", param,req,resp,ioc);
					JseView.view("index",null,obj, req, resp);
					return;
				}else {
					Object obj=nashornService.run(null, paths[0], param,req,resp,ioc);
					JseView.view(paths[0],null,obj, req, resp);
					return;
				}
				
			}else if(paths.length==2) {
				if(Strings.isNumber(paths[1])) {
					param.put("id", paths[1]);
					Object obj = nashornService.run(paths[0],paths[0], param,req,resp,ioc);
					JseView.view(paths[0],paths[0],obj, req, resp);
					return;
				}else if(Strings.isMatch(Pattern.compile("[\\u4e00-\\u9fa5]"), paths[1])){
					param.put("name", paths[1]);
					Object obj = nashornService.run(paths[0],paths[0], param,req,resp,ioc);
					JseView.view(paths[0],paths[0],obj, req, resp);
					return;
				}else {
					Object obj = nashornService.run(paths[0],paths[1], param,req,resp,ioc);
					JseView.view(paths[0],paths[1],obj, req, resp);
					return;
				}
			}else if(paths.length==3) {
				if(paths[0].equals("json")) {
					Object obj = nashornService.run(paths[1],paths[2], param,req,resp,ioc);
					resp.setContentType("application/json;charset=utf-8");
					resp.getWriter().println(Json.toJson(obj));
				}else if(paths[0].equals("raw")) {
					Object obj = nashornService.run(paths[1],paths[2], param,req,resp,ioc);
					if (obj instanceof File) {
						if (Lang.contains(Lang.array("png", "jpg", "webp", "xml", "json", "txt"), suffix)) {
							new RawView(suffix).render(req, resp, obj);
						} else {
							new RawView("application/octet-stream").render(req, resp, obj);
						}
					}else {
						resp.setContentType("text/plain;charset=utf-8");
						resp.getWriter().println(obj.toString());
					}
				}
				else if(Strings.isNumber(paths[2])) {
					param.put("id", paths[2]);
					Object obj = nashornService.run(paths[0],paths[1], param,req,resp,ioc);
					JseView.view(paths[0],paths[1],obj, req, resp);
				}else if(Strings.isMatch(Pattern.compile("[\\u4e00-\\u9fa5]"), paths[1])){
					param.put("name", paths[1]);
					Object obj = nashornService.run(paths[0],paths[0], param,req,resp,ioc);
					JseView.view(paths[0],paths[0],obj, req, resp);
					return;
				}else {
					param.put("id", paths[2]);
					Object obj = nashornService.run(paths[0],paths[1], param,req,resp,ioc);
					JseView.view(paths[0],paths[1],obj, req, resp);
				}
				return;
			}else if(paths.length==4) {
				if(Strings.isNumber(paths[1])) {
					param.put("id", paths[1]);
					Object obj = nashornService.run(paths[0],paths[0], param,req,resp,ioc);
					JseView.view(paths[0],paths[0],obj, req, resp);
					return;
				}else if(Strings.isMatch(Pattern.compile("[\\u4e00-\\u9fa5]"), paths[1])){
					param.put("name", paths[1]);
					Object obj = nashornService.run(paths[0],paths[0], param,req,resp,ioc);
					JseView.view(paths[0],paths[0],obj, req, resp);
					return;
				}else {
					param.put(paths[2], paths[3]);
					Object obj = nashornService.run(paths[0],paths[1], param,req,resp,ioc);
					JseView.view(paths[0],paths[1],obj, req, resp);
					return;
				}
				
			}else if(paths.length>4) {
				if(Strings.isNumber(paths[1])) {
					param.put("id", paths[1]);
				}else if(Strings.isMatch(Pattern.compile("[\\u4e00-\\u9fa5]"), paths[1])){
					param.put("name", paths[1]);
				}
				try {
					for (int i = 2; i < paths.length; i++) {
						param.put(paths[i], paths[i+1]);
						i++;
					}
				} catch (Exception e) {
					log.warnf("路径参数不对称,最后一位参数:%s没有val", paths[paths.length - 1]);
				}
				Object obj = nashornService.run(paths[0],paths[1], param,req,resp,ioc);
				JseView.view(paths[0],paths[1],obj, req, resp);
				return;
			}
		} catch (Throwable e) {
			log.errorf("err:%s", e);
		} finally {
			long end_time=System.currentTimeMillis();
			log.info(req.getServletPath()+" >>:"+(end_time-start_time)+"ms");
		}
		
		}
		chain.doFilter(req, resp);
	}

	

	@Override
	public void init(FilterConfig config) throws ServletException {
		config.getServletContext().getServletRegistration("default").addMapping("*.jsp","*.png","*.gif","*.jpg","*.jpeg","*.bmp","*.js",
		        "*.css","*.jspx","*.jpeg","*.htm","*.xhtml","*.mp3","*.mp4","*.ico","*.ttf","*.svg","*.jar","*.woff","*.eot","*.map");
		conf=new PropertiesProxy("jse.properties");
		ioc.put("conf", conf);
		Cache<Object, Object> cache=Caffeine.newBuilder().recordStats().maximumSize(10000)
				.expireAfterAccess(60, TimeUnit.MINUTES)
			    .expireAfterWrite(60, TimeUnit.MINUTES)//5分钟未更新丢失
			    .build();
		CacheService cacheService=new CacheService(cache);
		ioc.put("cache", cacheService);
		dataSource=conf.make(DruidDataSource.class, "db.");
		try {
			dataSource.init();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		dao=new Dao(dataSource);
		ioc.put("dao", dao);
		
		NashornScriptEngineFactory nashornFactory=new NashornScriptEngineFactory();
		NashornScriptEngine scriptEngine=(NashornScriptEngine) nashornFactory.getScriptEngine("--language=es6","--optimistic-types=[true]");
		ioc.put("scriptEngine", scriptEngine);
		nashornService=new NashornService();
		ioc.put("nashornService", nashornService);
		AliPay aliPay=new AliPay();
		aliPay.setConf(conf);
		aliPay.setDao(dao);
		ioc.put("aliPay", aliPay);
		WxPay wxPay=new WxPay();
		wxPay.setConf(conf);
		wxPay.setDao(dao);
		ioc.put("wxPay", wxPay);
	}
	
	@Override
	public void destroy() {
		if(dataSource!=null)
		dataSource.close();
	}

	private String getFilename(Part part) {  
        String contentDispositionHeader =   
                part.getHeader("content-disposition");  
        String[] elements = contentDispositionHeader.split(";");  
        for (String element : elements) {  
            if (element.trim().startsWith("filename")) {  
                return element.substring(element.indexOf('=') + 1)  
                        .trim().replace("\"", "");  
            }  
        }  
        return null;  
    }
}
